package com.xlh.wjdcserver.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.exception.QuestionnaireException;
import com.property.dto.*;
import com.property.entity.Option;
import com.property.entity.Question;
import com.property.entity.Questionnaire;
import com.property.vo.QuestionnaireAnalysisVO;
import com.property.vo.QuestionnairePageVO;
import com.property.vo.QuestionnaireVO;
import com.xlh.wjdcserver.mapper.OptionMapper;
import com.xlh.wjdcserver.mapper.QuestionMapper;
import com.xlh.wjdcserver.mapper.QuestionnaireMapper;
import com.xlh.wjdcserver.service.QuestionService;
import com.xlh.wjdcserver.service.QuestionnaireService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class QuestionnaireServiceImpl extends ServiceImpl<QuestionnaireMapper, Questionnaire> implements QuestionnaireService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private QuestionServiceImpl questionService;

    @Autowired
    private OptionServiceImpl optionService;


    @Override
    public void addQuestionnaire(QuestionnareDTO questionnareDTO) {
        Questionnaire questionnaire = new Questionnaire();
        BeanUtils.copyProperties(questionnareDTO, questionnaire);
        baseMapper.insert(questionnaire);

        // 删除缓存
        this.deleteCache();
    }

    @Override
    public void updateQuestionnaire(Questionnaire questionnaire) {
        if (questionnaire.getId() == null)
        {
            throw new QuestionnaireException("问卷id不能为空");
        }
        if(questionnaire.getStatus().equals("1"))
        {
            throw new QuestionnaireException("问卷已发布，不能修改");
        }
        baseMapper.updateById(questionnaire);
        if (questionnaire.getStatus().equals("0"))
        {
            baseMapper.updateAsign(questionnaire);
        }

        // 删除缓存
        this.deleteCache();
    }

    @Transactional
    @Override
    public void deleteQuestionnaire(List<QuestionnaireDelDTO> questionnaires) {
        // 删除问卷
        baseMapper.deleteByIds(questionnaires);
        // 删除问卷对应的问题
        List<String> questionnaireIds = questionnaires.stream().map(QuestionnaireDelDTO::getId).toList();
        questionService.deleteQuestions(questionnaireIds);

        // 删除问卷对应的选项
        questionService.deleteOptions(questionnaireIds);

        // 删除缓存
        this.deleteCache();
    }

    @Override
    public Page<QuestionnairePageVO> questionnaireDetail(QuestionPageDTO questionPageDTO) {
        Page<QuestionnairePageVO> page = new Page<>(questionPageDTO.getPage(), questionPageDTO.getSize());

        QueryWrapper<QuestionnairePageVO> queryWrapper = new QueryWrapper<>();

        // 获取分页数据
        Page<QuestionnairePageVO> resultPage = baseMapper.page(page, queryWrapper);

        List<QuestionnairePageVO> updatedRecords = resultPage.getRecords().stream()
                .map(questionnairePageVO -> {
                    questionnairePageVO.setQuestions(questionService.listQuestions(questionnairePageVO.getId()));
                    questionnairePageVO.setOptions(optionService.listOptions(questionnairePageVO.getId()));
                    return questionnairePageVO;
                })
                .collect(Collectors.toList());

        // 更新原始分页数据中的记录
        resultPage.setRecords(updatedRecords);


        // 返回分页结果
        return resultPage;
    }

    @Override
    public Page<Questionnaire> listQuestionnaire(QuestionPageDTO questionPageDTO) {

        boolean hasFilter =
                StrUtil.isNotBlank(questionPageDTO.getTitle()) ||
                        StrUtil.isNotBlank(questionPageDTO.getStatus()) ||
                        questionPageDTO.getCreateTimeStart() != null ||
                        questionPageDTO.getCreateTimeEnd() != null ||
                        questionPageDTO.getStartTime() != null ||
                        questionPageDTO.getEndTime() != null;


        // 去redis中获取数据
//        String key = "questionnaire:" + "page" + ":" + questionPageDTO.getPage() + ":" + questionPageDTO.getSize();
//        Object cache = redisTemplate.opsForValue().get(key);
//        if (cache != null)
//        {
//            // 缓存命中
//            return (Page<Questionnaire>) cache;
//        }

        // 缓存未命中
        Page<Questionnaire> page = new Page<>(questionPageDTO.getPage(), questionPageDTO.getSize());
        QueryWrapper<Questionnaire> queryWrapper = new QueryWrapper<>();
        if (!questionPageDTO.getTitle().isBlank())
        {
            queryWrapper.like("title", questionPageDTO.getTitle());
        }
        if (!questionPageDTO.getStatus().isBlank())
        {
            queryWrapper.eq("status", questionPageDTO.getStatus());
        }
        if (questionPageDTO.getCreateTimeStart() != null)
        {
            queryWrapper.ge("create_time", questionPageDTO.getCreateTimeStart());
        }
        if (questionPageDTO.getCreateTimeEnd() != null)
        {
            queryWrapper.le("create_time", questionPageDTO.getCreateTimeEnd());
        }
        if (questionPageDTO.getStartTime() != null)
        {
            queryWrapper.ge("start_time", questionPageDTO.getStartTime());
        }
        if (questionPageDTO.getEndTime() != null)
        {
            queryWrapper.le("end_time", questionPageDTO.getEndTime());
        }

        Page<Questionnaire> questionnairePage = baseMapper.selectPage(page, queryWrapper);
        questionnairePage.setTotal(questionnairePage.getRecords().size());
        // 更新缓存
//        redisTemplate.opsForValue().set(key, questionnairePage, 1, TimeUnit.MINUTES);

        return questionnairePage;

    }

    @Override
    public Page<Questionnaire> queryByQTitle(QuestionPageDTO questionPageDTO) {
        return this.listQuestionnaireWithCache(questionPageDTO);
    }

    @Transactional
    @Override
    public void asignQuestionnaire(QuestionnairePubDTO questionnairePubDTO) {
        if (questionnairePubDTO.getCompIds().isEmpty())
        {
            throw new QuestionnaireException("公司id不能为空");
        }
        baseMapper.asignQuestionnaire(questionnairePubDTO);

        Questionnaire questionnaire = new Questionnaire();
        BeanUtil.copyProperties(questionnairePubDTO, questionnaire, "createTime");
        questionnaire.setId(questionnairePubDTO.getQid());
        questionnaire.setStatus("1");
        baseMapper.updateById(questionnaire);
    }

    @Override
    public List<QuestionnaireAnalysisVO> questionnaireAnalysis(String qid) {
        if(qid == null)
        {
            throw new QuestionnaireException("问卷id不能为空");
        }
//        Questionnaire questionnaire = baseMapper.selectById(qid);
//        if (questionnaire.getStatus().equals("1"))
//        {
//            throw new QuestionnaireException("问卷发布中，请先停止发布！");
//        }
        QueryWrapper<QuestionnaireAnalysisVO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("que.delete_flag", '0');
        queryWrapper.eq("que.q_id", qid);
        List<QuestionnaireAnalysisVO> questionnaireAnalysisVOList = baseMapper.questionnaireAnalysis(queryWrapper);

        Map<String, QuestionnaireAnalysisVO> questionnaireAnalysisVOMap = new LinkedHashMap<>();
        questionnaireAnalysisVOList.forEach(questionnaireAnalysisVO ->{
            // 如果map中不存在该问题，则添加,按照问题id进行分类
            String queId = questionnaireAnalysisVO.getQueId();
            questionnaireAnalysisVOMap.putIfAbsent(queId, new QuestionnaireAnalysisVO());
            QuestionnaireAnalysisVO questionnaireAnalysisVO1 = questionnaireAnalysisVOMap.get(queId);

            // 初始化问题
            if (questionnaireAnalysisVO1.getQuestion() == null)
            {
                Question question = new Question();
                question.setId(queId);
                question.setContent(questionnaireAnalysisVO.getQueContent());
                question.setType(questionnaireAnalysisVO.getQueType());
                question.setQid(questionnaireAnalysisVO.getQid());
                question.setQueOrder(questionnaireAnalysisVO.getQueOrder());
                questionnaireAnalysisVO1.setQid(questionnaireAnalysisVO.getQid());
                questionnaireAnalysisVO1.setQuestion(question);
                questionnaireAnalysisVO1.setOptions(new ArrayList<>());
            }

            // 初始化选项
            OptionAnalysisDTO optionAnalysisDTO = new OptionAnalysisDTO();
            optionAnalysisDTO.setId(questionnaireAnalysisVO.getOptionId());
            optionAnalysisDTO.setOptionName(questionnaireAnalysisVO.getOptionName());
            optionAnalysisDTO.setOptionContent(questionnaireAnalysisVO.getOptionContent());
            optionAnalysisDTO.setCount(questionnaireAnalysisVO.getOptionCount());
            questionnaireAnalysisVO1.getOptions().add(optionAnalysisDTO);
        });

        return new ArrayList<>(questionnaireAnalysisVOMap.values());
    }

    @Override
    public QuestionnaireVO questionnaireStat() {
        List<Questionnaire> questionnaireList = baseMapper.selectList(new QueryWrapper<Questionnaire>().eq("delete_flag", '0'));

        QuestionnaireVO questionnaireVO = new QuestionnaireVO();
        questionnaireVO.setTotal(questionnaireList.size());
        questionnaireVO.setPublished(
                (int) questionnaireList.stream()
                        .filter(questionnaire -> questionnaire.getStatus().equals("1"))
                        .count()
        );
        questionnaireVO.setUnpublished(
                (int) questionnaireList.stream()
                        .filter(questionnaire -> questionnaire.getStatus().equals("0"))
                        .count()
        );
        questionnaireVO.setMonthNew(
                (int) questionnaireList.stream()
                        .filter(questionnaire -> questionnaire.getCreateTime().getMonth().equals(LocalDateTime.now().getMonth()))
                        .count()
        );
        return questionnaireVO;
    }


    // 删除缓存
    public void deleteCache()
    {
        Set<String> keys = redisTemplate.keys("questionnaire:page:*");
        redisTemplate.delete(keys);
    }

    // 解决缓存击穿问题
    public Page<Questionnaire> listQuestionnaireWithCache(QuestionPageDTO questionPageDTO)
    {
        String key = "questionnaire:" + "page" + ":" + questionPageDTO.getPage() + ":" + questionPageDTO.getSize() + ":" + questionPageDTO.getTitle();
//        String cacheJson = (String) redisTemplate.opsForValue().get(key);
        Object cache = redisTemplate.opsForValue().get(key);
        if (ObjectUtil.isNotEmpty(cache))
        {
//            return JSONUtil.toBean(cacheJson, Page.class);
            return (Page<Questionnaire>) cache;
        }


        // 如果缓存中是""值，抛出异常
        if (cache != null)
        {
            throw new QuestionnaireException("缓存击穿");
        }

        // 缓存未命中，查询数据库
        Page<Questionnaire> page = new Page<>(questionPageDTO.getPage(), questionPageDTO.getSize());
        QueryWrapper<Questionnaire> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("title", questionPageDTO.getTitle());
        Page<Questionnaire> questionnairePage = baseMapper.selectPage(page, queryWrapper);

        // 如果数据库中没有数据，则返回空
        if (questionnairePage.getRecords().isEmpty())
        {
            redisTemplate.opsForValue().set(key, "", 10, TimeUnit.SECONDS);
            return null;
        }

        // 如果有数据，更新缓存
        redisTemplate.opsForValue().set(key, questionnairePage, 1, TimeUnit.MINUTES);

        return questionnairePage;

    }

}
